﻿namespace ImageDupFinder.ProgramCore
{
    using System;
    using System.Collections.Generic;
    using System.IO;
    using System.Reflection;
    using ImageDupFinder.PluginCore;

    /// <summary>
    /// Class responsible for loading and managing plugins
    /// </summary>
    public class PluginManager
    {
        /// <summary>
        /// All loaded plugins.
        /// </summary>
        private readonly Dictionary<string, IPlugin> plugins;

        /// <summary>
        /// Initializes a new instance of the PluginManager class.
        /// </summary>
        public PluginManager()
        {
            this.plugins = new Dictionary<string, IPlugin>();
        }

        /// <summary>
        /// Initializes a new instance of the PluginManager class.
        /// </summary>
        /// <param name="path">path to plugins directory</param>
        /// <param name="host">plugins host</param>
        public PluginManager(string path, IPluginHost host)
            : this()
        {
            this.LoadPlugins(path, host);
        }

        /// <summary>
        /// Gets collection of loaded plugins.
        /// </summary>
        public Dictionary<string, IPlugin> Plugins
        {
            get { return this.plugins; }
        }

        /// <summary>
        /// Gets collection of currently enabled features.
        /// </summary>
        public IFeatureCollection[] EnabledFeatures
        {
            get
            {
                List<IFeatureCollection> features = new List<IFeatureCollection>(this.plugins.Count);
                foreach (IPlugin p in this.plugins.Values)
                {
                    if (p.Enabled)
                    {
                        features.Add(p);
                    }
                }

                return features.ToArray();
            }
        }

        /// <summary>
        /// Loads plugins
        /// </summary>
        /// <param name="path">path to plugins directory</param>
        /// <param name="host">plugins host</param>
        public void LoadPlugins(string path, IPluginHost host)
        {
            try
            {
                string[] pluginFiles = Directory.GetFiles(path, "*.DLL");
                for (int i = 0; i < pluginFiles.Length; i++)
                {
                    Assembly asm;
                    try
                    {
                        asm = Assembly.LoadFile(pluginFiles[i]);
                        Type[] types = asm.GetTypes();

                        if (asm != null)
                        {
                            foreach (Type t in types)
                            {
                                // Check if current type implements interface IPlugin
                                if (typeof(IPlugin).IsAssignableFrom(t) && !t.IsAbstract && t.IsClass)
                                {
                                    IPlugin p = (IPlugin)Activator.CreateInstance(t);
                                    p.Host = host;
                                    this.plugins.Add(p.Name, p);
                                    host.Register(p);
                                }
                            }
                        }
                    }
                    catch (Exception e)
                    {
                        // skip all bad plugins
                        System.Diagnostics.Debug.Write(String.Format("Plugin: {0}\nError: {1}", pluginFiles[i], e.ToString()));
                    }
                }
            }
            catch (UnauthorizedAccessException uae)
            {
                System.Diagnostics.Debug.Write(String.Format("Folder: {0}\nError: {1}", path, uae.ToString()));
            }
            catch (IOException ioe)
            {
                System.Diagnostics.Debug.Write(String.Format("Folder: {0}\nError: {1}", path, ioe.ToString()));
            }
        }
    }
}
